iT邦幫忙

2024 iThome 鐵人賽

DAY 26
0
Security

picoCTF 刷題分享系列 第 26

picoCTF 刷題分享---Day 26(ELF理論補足)

  • 分享至 

  • xImage
  •  

各位抱歉阿~~因為這個比賽影響到了我的學業了,經過再三的考量後,又不想放棄比賽😭😭
所以目前決定的是把解題變為理論的部分,會把以前運用到的一些知識,但因時間或篇幅而未詳談的
都會在接下來的幾天內做補充,希望可以苟延殘喘下去🫠🫠
收先來介紹在reverse中,最常遇到的ELF格式


ELF (Executable and Linkable Format)檔案結構簡介

ELF 檔案是一種在 Linux 和其他類 Unix 系統上使用的標準格式,它能夠儲存可執行檔、共享庫、以及目標檔案(Object Files)。這種格式的設計目的是允許不同模組和程式碼段在編譯和連結過程中進行互操作,進而形成一個可執行的程式。

  • 編譯過程
    • 高階語言 (Source Code):

      • 像 Python、C、C++、Java 等我們平常用來寫程式碼的語言,這些語言接近於人類的思維邏輯。
    • 編譯 (Compilation):

      • 編譯器(Compiler)將高階語言的程式碼轉換成組合語言,組合語言(Assembly Language)是一種低階語言,比較接近於機器語言,但仍然具有人類可讀的特性。
    • 彙編 (Assembly):

      • 組合語言器(Assembler)將組合語言轉換為機器碼(二進位(0,1)),這些指令可直接被處理器執行。這個過程會生成機器碼的中間檔案(通常稱為目標檔 Object File)。
    • 連結 (Linking):

      • 連結器(Linker)負責將多個目標檔案和函式庫整合為一個完整的可執行檔案(或共享庫)。這個步驟會將不同檔案中相互依賴的符號(如函式調用、全域變數等)進行解析和連結,最終形成一個 ELF 格式的可執行檔案。

ELF 檔案的主要段 (Section)
ELF 檔案包含了多個段(section),分別儲存各類資料:

.bss 段 (Block Started by Symbol):
這個段用來存放未初始化的全域變數或靜態變數。這些變數在程式開始執行時會被自動初始化為零,但 .bss 本身不佔用檔案大小,它只是記錄了需要初始化的變數數量。

.data 段:
這個段存放已經初始化的全域變數和靜態變數。當程式啟動時,這些變數的初始值會直接從 .data 段中載入記憶體。

.rodata 段 (Read-Only Data):
存放程式中的只讀資料,通常是常數值(如字串字面值、常數變數)。這些資料是不可修改的,防止在程式執行過程中被意外改動。

.text 段:
這個段儲存程式的可執行程式碼。所有的函式和執行邏輯都位於 .text 段中,它通常是唯讀的,這樣可以防止惡意程式修改程式碼段。

區域變數的存放位置
當函式被呼叫時,區域變數會被推入堆疊區(stack)並不會存放在 .bss 或 .data 段中,且當函式執行結束時,就會釋放堆疊。

連結器 (Linker) 的角色
連結器的主要任務是將不同的目標檔案(可能是由不同的源碼檔案編譯而成的)與所需的函式庫連結起來。它解決了程式中所有的符號定義與使用之間的依賴關係,確保最終的可執行檔案中的每一個符號都能正確引用到相應的程式碼或資料。連結器將這些段組織成一個整體,形成一個可執行的 ELF 檔案。


以下為白話文:
ELF:Executable and Linkable Format
我們平常在寫的叫做高階語言(python、C、c++、JAVA之類的),
他會經過compiler(中文叫編譯器) 進行 compile (中文叫編譯),
變成組合語言,組合語言是一種介於人類語言與機械語言(二進位的檔(0,1)),
再經過組合語言器變為一個目標檔案(Object file),一個目標檔案裡面會包含以下部分(section)

  1. .bss section:會把未定義(只宣告)的全域變數儲存在這裡
  2. .data section:會把已賦值的全域變數儲存在這裡
  3. .rodata section:這邊存的會是constant(常數),也就是唯讀的資料(.data存的是變數,他存的是值)
  4. .text section:他存的是function程式碼,所以只要是func.他都會存下來
    各位會發現我們經過組合語言器(assembler)進行彙編(assembly)後,產生目標檔案 (Object File) ,內會包含多個 sections,所以我們要把每一個section進行連結,這個步驟也就是要用到所謂的連結器(linker),把每一個函式或變數的定義與使用進行連結,這也是ELF中的L(Linkable)的由來。而區域變數會在呼叫函式時被push入堆疊,並在結束呼叫時被釋放。

這裡我有寫一個範例各位可以寫寫看
題目:

#include <stdio.h>
#include <iostream>

int a;
int b = 3;

int main()
{
    int b = 3;
    std::cout << "test text";
    return 0;
}

解答:

#include <stdio.h>
#include <iostream>
/*
標頭檔會在compile的時候,
會將所有用到的函式的符號放入目標檔案中,
接下來,連結器會將這些符號與相應的標準庫進行連結
*/

int a; //存到.bss
int b = 3; //b存到.data,3存到.rodata

int main()
{
    int b = 3; //放到堆疊(stack)裡,注意這是區域變數喔
    std::cout << "test text"; //"test text"存到.rodata
    return 0; //釋放堆疊 b、"test text"
}
//整個main會存到.text裡面

後記:
怎麼感覺這個更累🫠🫠


上一篇
picoCTF 刷題分享---Day 25(刷題去)
下一篇
picoCTF 刷題分享---Day 27(組語理論補足)
系列文
picoCTF 刷題分享30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言